package com.zjcode.cdcer.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.chinatechstar.component.commons.entity.MPage;
import com.chinatechstar.component.commons.result.PaginationBuilder;
import com.chinatechstar.component.commons.service.AliyunOssService;
import com.chinatechstar.component.commons.service.BaseService;
import com.chinatechstar.component.commons.supports.PageData;
import com.chinatechstar.component.commons.utils.ExcelUtils;
import com.chinatechstar.component.commons.utils.SnowflakeIdUtil;
import com.chinatechstar.component.commons.utils.UuidUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zjcode.cdcer.enums.CommonEnum;
import com.zjcode.cdcer.mapper.CerTreatmentInfoMapper;
import com.zjcode.cdcer.mapper.TkmSysOrgMapper;
import com.zjcode.cdcer.mapper.TkmSysUserMapper;
import com.zjcode.cdcer.model.*;
import com.zjcode.cdcer.model.basic.JsonObj;
import com.zjcode.cdcer.model.excel.SysteminitImportInfo;
import com.zjcode.cdcer.pojo.CerSysteminitImportInfo;
import com.zjcode.cdcer.service.CerSysteminitImportInfoService;
import com.zjcode.cdcer.service.CerTreatmentInfoService;
import com.zjcode.cdcer.service.SysDictService;
import com.zjcode.cdcer.service.SysUserService;
import com.zjcode.cdcer.utils.Utils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class CerTreatmentInfoServiceImpl implements CerTreatmentInfoService , BaseService {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private CerTreatmentInfoMapper cerTreatmentInfoMapper;
    @Autowired
    private CerSysteminitImportInfoService cerSysteminitImportInfoService;
    @Autowired
    private TkmSysOrgMapper orgMapper;

    @Autowired
    private TkmSysUserMapper userMapper;

    @Autowired
    private SysDictService sysDictService;

    @Autowired
    private SysUserService sysUserService;
    @Value("${studio.cer-personinfo-file-in-disk}")
    private String cerPersonFileInDisk;

    @Autowired
    private AliyunOssService aliyunOssService;
    /**
     * 新增治疗信息时，数据校验
     * @return 错误信息
     */
    @Override
    public StringBuilder addValidation() {
        StringBuilder errorMsg = new StringBuilder();
        errorMsg.append("联系人必填").append("|")
                .append("关系必填").append("|")
                .append("联系电话必填").append("|")
                .append("内镜检查信息必选").append("|")
                .append("记录人必选").append("|")
                .append("记录日期必填");
        return errorMsg;
    }

    @Override
    public int addBatchCerTreatmentInfo(List<CerTreatmentInfo> treatmentInfoList) {
        return cerTreatmentInfoMapper.addBatchCerTreatmentInfo(treatmentInfoList);
    }

    // 新增治疗信息
    @Override
    public void insertTreatment(CerTreatmentInfo cerTreatmentInfo) {
        // 主键
        String infoId = UuidUtil.get32UUID();
        // 默认：未发布0
        cerTreatmentInfo.setId(infoId);
        cerTreatmentInfo.setIsPublish(0);
        cerTreatmentInfo.setIsHaveError(1);
        cerTreatmentInfo.setErrorMessage(addValidation().toString());
        cerTreatmentInfoMapper.addCerTreatmentInfo(cerTreatmentInfo);
    }

    @Override
    public void updateTreatment(CerTreatmentInfo cerTreatmentInfo) {
        // 1、校验规则
        List<String> errors = Utils.dataValidationByTreatmentInfo(cerTreatmentInfo);
        if (errors.size() > 0) {
            cerTreatmentInfo.setIsHaveError(1);
            cerTreatmentInfo.setErrorMessage(errors.stream().collect(Collectors.joining("|")));
        } else {
            cerTreatmentInfo.setIsHaveError(0);
            cerTreatmentInfo.setErrorMessage("");
        }
        // 2、修改数据
        cerTreatmentInfoMapper.updateCerTreatmentInfoById(cerTreatmentInfo);
    }


    /**
     * BeanUtils的拷贝方法：只拷贝对象中属性值不为null的属性
     * @param source
     * @return
     */
    public static String[] getNullPropertyNames (Object source) {
        final BeanWrapper wrapper = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = wrapper.getPropertyDescriptors();
        Set<String> emptyNames = new HashSet<>();
        for(java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = wrapper.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    public CerTreatmentInfo getTreatmentById(String id){
        CerTreatmentInfo info=cerTreatmentInfoMapper.getCerTreatmentInfoById(id);
//        CerTreatmentInfo detail=cerTreatmentInfoMapper.getCerTreatmentDetailByInfoId(id);
//        BeanUtils.copyProperties(detail,info,getNullPropertyNames(detail));
        return info;
    }

    @Override
    public JsonObj findById(String id) {
        Map<String, Object> data = new HashMap<>();
        CerTreatmentInfo info = getTreatmentById(id);
        data.put(CommonEnum.RESP.getValue(), info);
        return JsonObj.success(data);
    }

    @Override
    public Integer getCountBysysteminitId(String systeminitId) {
        return cerTreatmentInfoMapper.getCountBysysteminitId(systeminitId);
    }

    @Override
    public Map<String, Object> findAllList(PageData pageData) {
        // 获取当前用户信息
        Long userId = Long.valueOf(pageData.get("user").toString());
        String extFlag = sysUserService.findUserExtFlag(String.valueOf(userId));
        pageData.put("extFlag", extFlag);
//        TkmSysUser userInfo = userMapper.selectByPrimaryKey(userId);
//        TkmSysOrg orgInfo = orgMapper.selectByPrimaryKey(userInfo.getOrgId());
//        pageData.put("ancestors", orgInfo.getAncestors().replace(",", "|"));
        // 解析分页参数
        MPage mPage = getPageInfo(pageData);
        Page<Object> page = PageHelper.startPage(mPage.getCurrentPage(), mPage.getPageSize());
        List<LinkedHashMap<String, Object>> list = cerTreatmentInfoMapper.findAllList(pageData);
        return PaginationBuilder.buildResult(list,
                page.getTotal(),
                mPage.getCurrentPage(),
                mPage.getPageSize());
    }

    @Override
    public JsonObj deleteById(String id) {
        int count=cerTreatmentInfoMapper.deleteById(id);
        if (count > 0) {
            return JsonObj.success("删除成功");
        } else {
            return JsonObj.error("删除失败");
        }
    }

    @Override
    public void updateTreatmentInfo(PageData pageData) {
        cerTreatmentInfoMapper.updateTreatmentInfoStatus(pageData);
    }

    @Override
    public List<CerTreatmentInfo> getTreatmentInfoByIds(List<String> ids) {
        return cerTreatmentInfoMapper.getTreatmentInfoByIds(ids);
    }

    @Override
    public List<LinkedHashMap<String, Object>> queryAllExportData(PageData pageData) {
        String userId = (String) pageData.get("user");
        Object idsData = pageData.get("ids");
        String extFlag = sysUserService.findUserExtFlag(String.valueOf(userId));
        pageData.put("extFlag", extFlag);
//        TkmSysUser userInfo = userMapper.selectByPrimaryKey(Long.valueOf(userId));
//        TkmSysOrg orgInfo = orgMapper.selectByPrimaryKey(userInfo.getOrgId());
//        pageData.put("ancestors", orgInfo.getAncestors().replace(",", "|"));
        // 获取extFlag
//        String extFlag = sysUserService.findUserExtFlag(userId);
        List<String> ids = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(idsData)) {
            ids =Arrays.asList(String.valueOf(idsData).split("\\|"));
        }
        List<LinkedHashMap<String, Object>> list = cerTreatmentInfoMapper.queryAllExportData(ids, idsData,pageData);

        // 查询数据自定并分组
        List<SysDict> allCerDicts = sysDictService.findAllCerDicts();
        Map<String, List<SysDict>> keyListMap = allCerDicts
                .stream()
                .collect(Collectors.groupingBy(SysDict::getDictType));
        keyListMap.entrySet().parallelStream().forEach(entry -> {
            // key
            String key = entry.getKey();
            List<SysDict> dicts = entry.getValue();
            list.parallelStream().forEach(item->{
                Object o = item.get(key);
                if (o!=null) {
                    Optional<SysDict> first = dicts.stream()
                            .filter(sysDict -> sysDict.getDictValue().equals(o.toString())).findFirst();
                    first.ifPresent(sysDict -> {
                        item.put(key, sysDict.getDictName());
                    });
                }
            });
        });

        return list;
    }

    @Override
    public String setDyeCode(String dye){
        if (ObjectUtils.isEmpty(dye)) {
            return "";
        }else if (Objects.equals(dye.trim(), "未染")) {
            return "0";
        } else if (Objects.equals(dye.trim(), "碘染色")) {
            return "1";
        }  else if (Objects.equals(dye.trim(), "靛胭脂染色")) {
            return "2";
        }  else if (Objects.equals(dye.trim(), "电子增强（包括NBI或FICE或iSCAN）")) {
            return "3";
        }  else if (Objects.equals(dye.trim(), "碘染色+靛胭脂染色")) {
            return "4";
        }  else if (Objects.equals(dye.trim(), "靛胭脂染色+电子增强")) {
            return "5";
        }  else if (Objects.equals(dye.trim(), "碘染色+电子增强")) {
            return "6";
        }  else if (Objects.equals(dye.trim(), "碘染色+靛胭脂染色+电子增强")) {
            return "7";
        }
        return "";
    }

    @Override
    public String setIsHj(String isHj){
        if (ObjectUtils.isEmpty(isHj)) {
            return "";
        } else if (Objects.equals(isHj.trim(), "是")) {
            return "1";
        } else if (Objects.equals(isHj.trim(), "否")) {
            return "2";
        }
        return "";
    }

    @Override
    public void setIsPublishByInfoIds(List<String> ids) {
        cerTreatmentInfoMapper.setIsPublishByInfoIds(ids);
    }

    @Override
    public List<CerTreatmentInfo> getDataByInitId(String id) {
        return cerTreatmentInfoMapper.getDataByInitId(id);
    }

    @Override
    public CerTreatmentInfo getTreatmentInfo(TkmSysteminitImportInfo importInfo) {
        CerTreatmentInfo cerTreatmentInfo = new CerTreatmentInfo();
//        cerTreatmentInfo.setTreatmentInfoId(importInfo.getId());
        cerTreatmentInfo.setId(UuidUtil.get32UUID());
        cerTreatmentInfo.setSysteminitId(importInfo.getId());
        //病例代碼
        cerTreatmentInfo.setSgblCode(importInfo.getSgblCode());
        cerTreatmentInfo.setBmblCode(importInfo.getBmblCode());
        cerTreatmentInfo.setWblCode(importInfo.getWblCode());
        cerTreatmentInfo.setSezcCode(importInfo.getSezcCode());
        // 内镜检查（是1、否2）
        cerTreatmentInfo.setNjjc(StringUtils.isNotEmpty(importInfo.getNjNum())?"1":"2");
        // 染色类别
        cerTreatmentInfo.setDye(importInfo.getDye());
        // 是否活检
        cerTreatmentInfo.setIsHj(importInfo.getIsHj());
        // 病理诊断医师
        cerTreatmentInfo.setBlzdStaff(importInfo.getBlzdStaff());
        return cerTreatmentInfo;
    }

    /**
     * 治疗信息只获取表格中的：id 、initId、sgblCode、bmblCode、wblCode、sezcCode、
     *                     njjc【求的，根据是否有内镜号判断】、dye、isHj、blzdStaff
     * @param file
     * @param response
     * @param userId
     * @return
     */
    @Override
    public JsonObj importGJData(MultipartFile file, HttpServletResponse response, String userId) {
        ImportParams params = new ImportParams();
        params.setTitleRows(0);
        File tmpfile =cerSysteminitImportInfoService.commonImportConfig(file,userId);
        // 解析excel
        List<SysteminitImportInfo> list = ExcelImportUtil.importExcel(tmpfile, SysteminitImportInfo.class, params);
        // 数据过滤,国家来源的数据默认都是正确的，仅过滤名称为null的
        list = list.stream().filter(each -> StringUtils.isNotEmpty(each.getName()) && !Objects.equals("测试",each.getName())).collect(Collectors.toList());
        int count = 0;
        // 执行数据写入
        List<LinkedHashMap<String, Object>> failList =new ArrayList<>();
        if (list.size() > 0) {
            List<CerSysteminitImportInfo> infos=cerSysteminitImportInfoService.getAllInitImports();
            // 提取两个实体列表中的某个字段,排除不在系统中的数据【noSystemIds查的是：在插入的表格里，却不在系统里】
            list.forEach(item->{
                item.setErrorFlag(1);
                infos.forEach(each->{
                    if (Objects.equals(item.getScreeningId(),each.getScreeningId())) {
                        String initId = each.getId();
                        if (getCountBysysteminitId(initId) > 0){
                            failList.add(cerSysteminitImportInfoService.getLinkedMapByList(item,"系统中已经有治疗操作"));
                            item.setErrorFlag(2);
                        }
                        item.setInitId(initId);
                    }
                });
            });
            // 过滤：在导入的Excel中，却不在系统中的screeningId集合
            List<String> noSystemIds = list.stream()
                    .map(SysteminitImportInfo::getScreeningId)
                    .filter(screeningId -> infos.stream()
                            .map(CerSysteminitImportInfo::getScreeningId)
                            .noneMatch(existingScreeningId -> existingScreeningId.equals(screeningId)))
                    .collect(Collectors.toList());
            for (SysteminitImportInfo item : list) {
                for (String systemId : noSystemIds) {
                    // 将不在系统中的数据，报错提示在文件中
                    if (Objects.equals(systemId,item.getScreeningId())) {
                        failList.add(cerSysteminitImportInfoService.getLinkedMapByList(item,"对象ID调查号,系统中不存在，先上报后才能治疗操作"));
                        item.setErrorFlag(2);
                    }
                }
            }
            // 成功的数据（过滤 errorFlag == 1成功），批量新增
            list = list.stream().filter(each -> each.getErrorFlag()==1).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(list)) {
                List<CerTreatmentInfo> infoList=new ArrayList<>();
                for (SysteminitImportInfo info : list) {
                    // 治疗信息只获取id 、initId、sgblCode、bmblCode、wblCode、sezcCode、njjc【求的，根据是否有内镜号判断】、dye、isHj、blzdStaff
                    CerTreatmentInfo cerTreatmentInfo = new CerTreatmentInfo();
                    cerTreatmentInfo.setId(UuidUtil.get32UUID());
                    cerTreatmentInfo.setSysteminitId(info.getInitId());
                    //病例代碼
                    cerTreatmentInfo.setSgblCode(info.getSgblCode());
                    cerTreatmentInfo.setBmblCode(info.getBmblCode());
                    cerTreatmentInfo.setWblCode(info.getWblCode());
                    cerTreatmentInfo.setSezcCode(info.getSezcCode());
                    // 内镜检查（是1、否2）
                    cerTreatmentInfo.setNjjc(StringUtils.isNotEmpty(info.getNjNum())?"1":"2");
                    // 染色类别
                    cerTreatmentInfo.setDye(setDyeCode(info.getDye()));
                    // 是否活检
                    cerTreatmentInfo.setIsHj(setIsHj(info.getIsHj()));
                    // 病理诊断医师
                    cerTreatmentInfo.setBlzdStaff(info.getBlzdStaff());
                    cerTreatmentInfo.setIsPublish(0);
                    cerTreatmentInfo.setIsHaveError(1);
                    cerTreatmentInfo.setErrorMessage(addValidation().toString());
                    cerTreatmentInfo.setCountrySource("1");
                    infoList.add(cerTreatmentInfo);
                }
                count = cerTreatmentInfoMapper.addBatchCerTreatmentInfo(infoList);
            }
        }
        // 组装表头
        List<String> headList = Arrays.asList(
                "省份",
                "城市",
                "区县",
                "乡镇",
                "村",
                "机构名称",
                "调查对象ID号",
                "姓名",
                "性别",
                "生日",
                "民族",
                "身份证号",
                "地址",
                "联系电话",
                "筛查类型",
                "随访次数",
                "内镜号",
                "是否无痛",
                "染色类别",
                "是否活检",
                "内镜诊疗日期",
                "Hp",
                "Hp检测方法",
                "图片数量",
                "内镜诊断",
                "内镜诊断医师",
                "内镜审核医师",
                "病理号",
                "病理报告日期",
                "食管病理诊断代码",
                "贲门病理诊断代码",
                "胃病理诊断代码",
                "十二指肠病理诊断代码",
                "病理诊断医师",
                "病理审核医师",
                "病理诊断",
                "导入错误原因");
        try {
            // 导出
            if (CollectionUtils.isNotEmpty(failList)) {
//                String s = ExcelUtils.downloadExcel(headList, failList, "导入失败数据导出", response, cerPersonFileInDisk);
                File downloadExcelFile = ExcelUtils.downloadExcelFile(headList, failList, "导入失败数据导出", response, cerPersonFileInDisk);
                String upload = aliyunOssService.upload(downloadExcelFile);
                HashMap<String,Object> res =new HashMap<>();
                res.put("errorFile", upload);
                String msg ="导入失败"+failList.size()+"条";
                if (count>0) {
                    msg += "，导入成功"+count+"条数据";
                }
                return JsonObj.success(res,msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return JsonObj.error("错误数据导出失败");
        }
        return JsonObj.success("导入成功"+count+"条数据");
    }

    @Override
    public List<CerTreatmentInfo> getTreatmentByInitId(List<String> initIds) {
        return cerTreatmentInfoMapper.getTreatmentByInitId(initIds);
    }


}
